﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MPI;

namespace SVM {
    /// <summary>
    /// Used to stroe a list of ReceiveRequest
    /// When calling Test or Wait method, if any request is completed,
    /// they will be removed from internal list and passed as return values.
    /// Note : Except for TestAll() method, will not remove any request, and only return a bool value.
    /// </summary>
    public class ReceiveRequestList : List<ReceiveRequest> {
        
        ///// <summary>
        ///// Create a new, empty ReceiveRequest list.
        ///// </summary>
        //public ReceiveRequestList() : base() { }


        /// <summary>
        /// Waits until any ReceiveRequest has completed. That ReceiveRequest will then be removed 
        /// from the ReceiveRequest list and returned.
        /// </summary>
        /// <returns>The completed ReceiveRequest, which has been removed from the ReceiveRequest list.</returns>
        public ReceiveRequest WaitAny()
        {
            if (this.Count == 0)
                throw new ArgumentException("Cannot call MPI.RequestList.WaitAny with an empty ReceiveRequest list");

            while (true)
            {
                ReceiveRequest req = TestAny();
                if (req != null)
                    return req;
            }
        }

        /// <summary>
        /// Determines whether any ReceiveRequest has completed. If so, that ReceiveRequest will be removed
        /// from the ReceiveRequest list and returned. 
        /// </summary>
        /// <returns>
        ///   The first ReceiveRequest that has completed, if any. Otherwise, returns <c>null</c> to
        ///   indicate that no ReceiveRequest has completed.
        /// </returns>
        public ReceiveRequest TestAny()
        {
            int n = this.Count;
            for (int i = 0; i < n; ++i)
            {
                ReceiveRequest req = this[i];
                if (req.Test() != null)
                {
                    this.RemoveAt(i);
                    return req;
                }
            }

            return null;
        }

        /// <summary>
        /// Wait until all of the requests has completed before returning.
        /// </summary>
        /// <returns>A list containing all of the completed requests.</returns>
        public ReceiveRequestList WaitAll()
        {
            ReceiveRequestList result = new ReceiveRequestList();
            while (this.Count > 0)
            {
                ReceiveRequest req = WaitAny();
                result.Add(req);
            }
            return result;
        }

        /// <summary>
        /// Test whether all of the requests have completed. If all of the
        /// requests have completed, the result is the true, and every 
        /// request in the list is valid to get a value.
        /// Otherwise, the result is <c>false</c>.
        /// </summary>
        /// <returns>Either the list of all completed requests, or null.</returns>
        public bool TestAll()
        {
            int n = this.Count;
            for (int i = 0; i < n; ++i)
            {
                if (this[i].Test() == null)
                    return false;
            }
            return true;
        }

        /// <summary>
        /// Wait for at least one ReceiveRequest to complete, then return a list of
        /// all of the requests that have completed at this point.
        /// </summary>
        /// <returns>
        ///   A list of all of the requests that have completed, which
        ///   will contain at least one element.
        /// </returns>
        public ReceiveRequestList WaitSome()
        {
            if (this.Count == 0)
                throw new ArgumentException("Cannot call MPI.RequestList.WaitAny with an empty ReceiveRequest list");

            ReceiveRequestList result = new ReceiveRequestList();
            while (result.Count == 0)
            {
                int n = this.Count;
                for (int i = 0; i < n; ++i)
                {
                    ReceiveRequest req = this[i];
                    if (req.Test() != null)
                    {
                        this.RemoveAt(i);
                        --i;
                        --n;
                        result.Add(req);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Return a list of all requests that have completed.
        /// </summary>
        /// <returns>
        ///   A list of all of the requests that have completed. If
        ///   no requests have completed, returns <c>null</c>.
        /// </returns>
        public ReceiveRequestList TestSome()
        {
            ReceiveRequestList result = null;
            int n = this.Count;
            for (int i = 0; i < n; ++i)
            {
                ReceiveRequest req = this[i];
                if (req.Test() != null)
                {
                    this.RemoveAt(i);
                    --i;
                    --n;

                    if (result == null)
                        result = new ReceiveRequestList();
                    result.Add(req);
                }
            }
            return result;
        }

    }
}
